package com.txby.common.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.PathMatcher;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * Spring Context 工具类
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {
	public static ApplicationContext applicationContext;
	/**
	 * 注册的Controller的所有方法对象
	 */
	private static Method detectHandlerMethodsMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class,
			"detectHandlerMethods", Object.class);
	/**
	 * 注册的Controller的映射所有方法对象
	 */
	private static Method getMappingForMethodMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class,
			"getMappingForMethod", Method.class, Class.class);
	/**
	 * 注册的Controller的映射path所有方法匹配对象
	 */
	private static Method getMappingPathPatternsMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class,
			"getMappingPathPatterns", RequestMappingInfo.class);
	/**
	 * 注册的Controller的映射path所有方法对象
	 */
	private static Method getPathMatcherMethod = ReflectionUtils.findMethod(RequestMappingHandlerMapping.class,
			"getPathMatcher");
	/**
	 * 注册的Controller的映射所有方法字段对象
	 */
	private static Field injectionMetadataCacheField = ReflectionUtils
			.findField(AutowiredAnnotationBeanPostProcessor.class, "injectionMetadataCache");

	private static ConfigurableApplicationContext configurableContext;
	private static DefaultListableBeanFactory beanDefinitionRegistry;

	static {
		getMappingForMethodMethod.setAccessible(true);
		detectHandlerMethodsMethod.setAccessible(true);
		detectHandlerMethodsMethod.setAccessible(true);
		getMappingForMethodMethod.setAccessible(true);
		getMappingPathPatternsMethod.setAccessible(true);
		getPathMatcherMethod.setAccessible(true);
		injectionMetadataCacheField.setAccessible(true);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringContextUtils.applicationContext = applicationContext;
		configurableContext = (ConfigurableApplicationContext) SpringContextUtils.applicationContext;
		beanDefinitionRegistry = (DefaultListableBeanFactory) configurableContext.getBeanFactory();
	}
	/**
	 * 根据名称注册容器对象
	 */
	public static void registerBeanNew(String beanName, Class<?> beanClass) {
		org.springframework.beans.factory.support.GenericBeanDefinition bd = new org.springframework.beans.factory.support.GenericBeanDefinition();
		bd.setBeanClass(beanClass);
		if (StringUtils.hasText(beanName)) {
			beanDefinitionRegistry.registerBeanDefinition(beanName, bd);
		} else {
			BeanDefinitionReaderUtils.registerWithGeneratedName(bd, beanDefinitionRegistry);
		}

	}
	/**
	 * 根据类型注册容器对象
	 */
	public static void registerBean(Class<?> beanClass) {
		registerBeanNew(null, beanClass);
	}

	/**
	 * 根据名称注册容器对象
	 */
	public static void registerBean(String beanName, Class requiredType) {
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
				.genericBeanDefinition(requiredType.getName());
		BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
		beanDefinition.setScope("singleton");
		beanDefinition.setLazyInit(false); // 设置是否懒加载
		beanDefinition.setAutowireCandidate(true);
		beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
	}
	/**
	 * 根据名称注册Controller
	 */
	public static void registerController(Class<?> controllerClass) {
		if (beanDefinitionRegistry.containsBean(controllerClass.getName())) {
			return;
		}
		Assert.notNull(controllerClass, "register controller bean class must not null");
		if (!WebApplicationContext.class.isAssignableFrom(applicationContext.getClass())) {
			throw new IllegalArgumentException("applicationContext must be WebApplicationContext type");
		}

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setBeanClass(controllerClass);

		String controllerBeanName = controllerClass.getName();
		beanDefinitionRegistry.registerBeanDefinition(controllerBeanName, bd);
		RequestMappingHandlerMapping requestMappingHandlerMapping = requestMappingHandlerMapping();
		ReflectionUtils.invokeMethod(detectHandlerMethodsMethod, requestMappingHandlerMapping, controllerBeanName);
	}
	/**
	 * 根据名称移除旧的Controller对象
	 */
	private static void removeOldControllerMapping(String controllerBeanName) {

		if (!beanDefinitionRegistry.containsBean(controllerBeanName)) {
			return;
		}
		RequestMappingHandlerMapping requestMappingHandlerMapping = requestMappingHandlerMapping();
		// remove old
		Class<?> handlerType = applicationContext.getType(controllerBeanName);
		final Class<?> userType = ClassUtils.getUserClass(handlerType);

		RequestMappingHandlerMapping innerRequestMappingHandlerMapping = requestMappingHandlerMapping;

		Map<RequestMappingInfo, HandlerMethod> handlerMethods = innerRequestMappingHandlerMapping.getHandlerMethods();
		Collections.unmodifiableMap(handlerMethods);
		for (RequestMappingInfo rmi : handlerMethods.keySet()) {
			PatternsRequestCondition prc = rmi.getPatternsCondition();
			HandlerMethod hm = handlerMethods.get(rmi);
			hm.getMethod().setAccessible(true);
			Set<String> patterns = prc.getPatterns();
			for (String uStr : patterns) {
				System.err.println(uStr);
				if (uStr.equals("/controller")) {
					// handlerMethods.remove(rmi);
				}
			}
		}
		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new ReflectionUtils.MethodFilter() {
			@Override
			public boolean matches(Method method) {
				return ReflectionUtils.invokeMethod(getMappingForMethodMethod, innerRequestMappingHandlerMapping,
						method, userType) != null;
			}
		});

		for (Method method : methods) {
			RequestMappingInfo mapping = (RequestMappingInfo) ReflectionUtils.invokeMethod(getMappingForMethodMethod,
					requestMappingHandlerMapping, method, userType);
			if (handlerMethods.containsKey(mapping)) {
				handlerMethods.remove(mapping);
			}

			Set<String> patterns = (Set<String>) ReflectionUtils.invokeMethod(getMappingPathPatternsMethod,
					requestMappingHandlerMapping, mapping);

			PathMatcher pathMatcher = (PathMatcher) ReflectionUtils.invokeMethod(getPathMatcherMethod,
					requestMappingHandlerMapping);

			for (String pattern : patterns) {
				if (!pathMatcher.isPattern(pattern)) {
					System.out.println(pattern);
					// urlMapping.remove(pattern);
				}
			}
		}

	}
	/**
	 * 根据名称移除Controller对象
	 */
	private static void removeControllerMapping(String controllerBeanName) {
		RequestMappingHandlerMapping requestMappingHandlerMapping = requestMappingHandlerMapping();
		beanDefinitionRegistry.removeBeanDefinition(applicationContext.getType(controllerBeanName).getName());
	}
	/**
	 * 获取当前请求映射方法对象
	 */
	private static RequestMappingHandlerMapping requestMappingHandlerMapping() {
		try {
			return applicationContext.getBean(RequestMappingHandlerMapping.class);
		} catch (Exception e) {
			throw new IllegalArgumentException("applicationContext must has RequestMappingHandlerMapping");
		}
	}
	/**
	 * 添加Controller映射path
	 */
	private static void addControllerMapping(String controllerBeanName) {
		removeControllerMapping(controllerBeanName);
		RequestMappingHandlerMapping requestMappingHandlerMapping = requestMappingHandlerMapping();
		requestMappingHandlerMapping.getClass().getFields();
		ReflectionUtils.invokeMethod(detectHandlerMethodsMethod, requestMappingHandlerMapping, controllerBeanName);
	}
	/**
	 * 根据名称获取容器对象
	 */
	public static Object getBean(String name) {
		return applicationContext.getBean(name);
	}
	/**
	 * 根据类型获取容器对象
	 */
	public static Object getBean(Class  requiredType) {
		return applicationContext.getBean(requiredType);
	}
	/**
	 * 根据名称反射获取容器对象
	 */
	public static <T> T getBean(String name, Class<T> requiredType) {
		return applicationContext.getBean(name, requiredType);
	}
	/**
	 * 是否含有容器对象
	 */
	public static boolean containsBean(String name) {
		return applicationContext.containsBean(name);
	}
	/**
	 * 是否单例容器对象
	 */
	public static boolean isSingleton(String name) {
		return applicationContext.isSingleton(name);
	}
	/**
	 * 根据名称获取容器对象的反射类型
	 */
	public static Class<? extends Object> getType(String name) {
		return applicationContext.getType(name);
	}
	
	/**
	 * 根据名称移除容器对象
	 */
    public static void unregisterBean(String beanName){
        beanDefinitionRegistry.removeBeanDefinition(beanName);
    }
	
	 

}